use std::collections::HashMap;
use std::fmt::Display;

trait Observer<E> : Display
{
    fn notify(&self, e: &E) -> bool;
}

struct Observers<E> 
where E: Display
{
    observers: HashMap<String, Box<dyn Observer<E>>>,
}

impl<E> Default for Observers<E> 
where E: Display
{
    fn default() -> Self {
        Self {
            observers: HashMap::new(),
        }
    }
}
impl<E> Observers<E>
where E: Display
{
    fn insert(&mut self, observer: Box<dyn Observer<E>>)->Option<Box <dyn Observer<E>>>{
        self.observers.insert(observer.to_string(), observer)
    }
    fn remove(&mut self, name:&str) -> Option<Box<dyn Observer<E>>>{
        self.observers.remove(name)
    }
    fn clear(&mut self){
        self.observers.clear()
    }
    fn contains_key(&self, name:&str) -> bool{
        self.observers.contains_key(name)
    }
    fn iter(&self) -> std::collections::hash_map::Iter<'_, String, Box<dyn Observer<E>>> {
        self.observers.iter()
    }
    fn iter_mut(&mut self) -> std::collections::hash_map::IterMut<'_, String, Box<dyn Observer<E>>>{
        self.observers.iter_mut()
    }
    fn len(&self) -> usize {
        self.observers.len()
    }
    fn get(&self, name:&str) -> Option<&Box<dyn Observer<E>>>{
        self.observers.get(name)
    }
}

trait Subject<E> 
where E: Display
{
    fn update(&self, e: &E) -> bool {
        self.observers().iter().try_for_each(|(_, v)| {
            if v.notify(e) {
                ControlFlow::Continue(())
            }
            else{
                ControlFlow::Break(())
            }
        }).is_continue()
    }

    fn attach<O>(&mut self, observer: O)
    where O: Observer<E> + 'static
    {
        self.observers_mut().insert(Box::new(observer));
    }
    fn detach(&mut self, name: &str)
    {
        self.observers_mut().remove(name);
    }
    fn len(&self) -> usize {
        self.observers().len()
    }
    fn get(&self, name: &str) -> Option<&dyn Observer<E>>{
        self.observers().get(name).map(|ptr| &**ptr)
    }


    fn observers_mut(&mut self) -> &mut Observers<E>;
    fn observers(&self) -> &Observers<E>;
}






#[derive(Debug)]
struct Event {
    name: String,
}

impl Display for Event {
    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(fmt, "{}", &self.name)
    }
}
impl Event {
    fn new(name: &str) -> Self {
        Self { 
            name: name.to_owned()
        }
    }
}





struct MyObserver1 {
}
impl Display for MyObserver1 {
    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(fmt, "Observer---1")
    }
}
impl Observer<Event> for MyObserver1{
    fn notify(&self, e: &Event) -> bool {
        println!("{}:{}", self.to_string(), e.to_string());
        true
    }
}

struct MyObserver{
    name: String
}
impl Display for MyObserver {
    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(fmt, "{}", &self.name)
    }
}
impl Observer<Event> for MyObserver 
{
    fn notify(&self, e: &Event) -> bool{
        println!("{}:{}", self.to_string(), e.to_string());
        true
    }
}
impl MyObserver {
    fn new(name: &str) -> Self {
        Self { 
            name: name.to_owned(),
        }
    }
}


use std::ops::ControlFlow;

#[derive(Default)]
struct MySubject {
    data: Observers<Event>,
}

impl Subject<Event> for MySubject
{
    fn observers_mut(&mut self) -> &mut Observers<Event> {
        &mut self.data
    }
    fn observers(&self) -> &Observers<Event> {
        &self.data
    }
}

impl Drop for MySubject{
    fn drop(&mut self) {
        self.observers_mut().clear()
    }
}






#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn test(){
        let mut subject = MySubject::default();
        subject.attach(MyObserver::new("observer1"));
        subject.attach(MyObserver::new("observer2"));
        subject.attach(MyObserver1{});
        assert_eq!(3, subject.len());
        subject.get("observer1")
            .map(|o| {
                println!("get_observer from subject.....{}", o.to_string())
            });

        subject.update(&Event::new("event1"));
        subject.update(&Event::new("event2"));


        subject.detach("observer1");
        assert_eq!(2, subject.len());
    }
}
